
/* GCSx
** TEXTURE.H
**
** Texture-management for OpenGL
*/

/*****************************************************************************
** Copyright (C) 2003-2006 Janson
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
*****************************************************************************/

#ifndef __GCSx_TEXTURE_H_
#define __GCSx_TEXTURE_H_

// TextureMap class: Allocates textures to graphics as efficiently as possible.
// Internally, may be any number of textures, subtextures of one or more textures,
// share subtextures from other textures, etc.
class TextureMap {
private:
    int dispWidth;
    int dispHeight;
    int graphicCount;
    int multiTexture; // if >1, more than one texture per graphic (due to size)
    
    struct TexturePos {
        // Texture number
        GLuint tex;
        // Sub-texture number (not part of OpenGL)
        // < 0 = self-contained texture, not in global list
        int subtex;
        // Position within texture
        GLfloat x1, x2, y1, y2;
        GLint x, y;
    };
    
    TexturePos* graphics;
    
    // Cached updates
    std::map<int, Uint8*> updates;
    
    // Global texture list for textures with >1 sub-texture
    struct TextureList {
        GLuint tex;
        int subtexW, subtexH;
        int subtexCount;
        std::map<int, int> inUse;
    };
    static std::vector<TextureList>* globalTextures;
    
    // Upscale to nearest power of two IF textures must be powers of two
    // Also clips to minSize (but only asserts for maxSize!)
    static int optionalPowerOfTwo(int val);
    
    // All existing texture maps that need updating form a circular double-linked list
    // A standalone texture needing updating points to itself
    // Textures that don't need to update have NULL pointers here
    TextureMap* nextUpdate;
    TextureMap* prevUpdate;
    static TextureMap* headUpdate;
    void removeFromUpdates();
    
    // These optimizations assume all texture display goes through a Texture class
    static GLuint lastTexture;
    
public:
    // How many graphics of what size?
    // Can optionally pass surface/function that will provide all surface info now
    // (will pass numbers starting at 1)
    // EXPECTS SURFACE32s
    TextureMap(int count, int width, int height,
               void (*tileCoords)(int position, const SDL_Surface*& src, int& x, int& y) = NULL);
    ~TextureMap();
    
    // Store a graphic- does not retain pointer
    // Indexed starting at 1 to correspond to tiles, sprites, etc.
    // Assumes 32bit RGBA surface
    // Must call updateTexture() when done with all updates
    void store(int graphic, const SDL_Surface* src, int sx = 0, int sy = 0, int dx = 0, int dy = 0, int dw = -1, int dh = -1);
    
    // Perform any/all texture updates now, for this texture map only
    void updateTexture();
    
    // Perform all texture updates for ALL existing texture maps
    static void updateAllTextures();
    
    // Draws graphic onscreen
    // Indexed starting at 1 to correspond to tiles, sprites, etc.
    void draw(int graphic, GLint x, GLint y) const;
    void drawScale(int graphic, GLfloat x, GLfloat y, GLfloat scale) const;
    // orient matches LAYER_TILE_* constants (flip, mirror, rotate)
    enum {
        TEXTURE_FLIP = 0x10000000,
        TEXTURE_MIRROR = 0x20000000,
        TEXTURE_ROTATE = 0x40000000,
    };
    void draw(int graphic, GLint x, GLint y, int orient) const;
    
    // Draws graphic with clipping hints (ignorable)
    // (clipping in screen coordinates, not graphic coordinates)
    void draw(int graphic, GLint x, GLint y, Rect clip) const;

    // Given X textures of YxZ, detemine best size(s) of textures to store them on
    // Doesn't work for textures larger than largest texture size
    // Public for testing purposes
    struct tGroup {
        int texW, texH, countW, countH;
        // Number of this texture size to do
        int qty;
    };
    // (returns total texture count)
    static int groupTextures(int count, int w, int h, std::vector<tGroup>& sizes);
    
    // Must call when initializing GL to set up optimizations
    // (currently no 'exit' function is needed)
    static void setupOptimizations();
};

#endif
